package com.zenchn.shiro;


import com.zenchn.model.*;
import com.zenchn.service.AccountRoleMapperService;
import com.zenchn.service.AccountService;
import com.zenchn.service.RoleAuthorityMapperService;
import com.zenchn.service.RoleService;
import com.zenchn.utils.IPUtils;
import com.zenchn.utils.Ip2RegionUtils;
import com.zenchn.utils.PwdHashSaltUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 用户身份验证,授权 Realm 组件
 *
 * @author panbingqi
 * @date 2021-06-01
 **/
public class SecurityRealm extends AuthorizingRealm {

    @Autowired
    @Lazy
    private AccountService accountService;

    @Autowired
    @Lazy
    private RoleService roleService;


    @Autowired
    @Lazy
    private AccountRoleMapperService accountRoleMapperService;

    @Autowired
    @Lazy
    private RoleAuthorityMapperService roleAuthorityMapperService;

    /**
     * 权限检查
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        TSysAccount account = (TSysAccount) principals.getPrimaryPrincipal();

        TSysAccountRoleMapperExample accountRoleMapperExample=new TSysAccountRoleMapperExample();
        accountRoleMapperExample.createCriteria().andAccountIdEqualTo(account.getAccountId());
        List<TSysAccountRoleMapper> accountRoleMapperList=accountRoleMapperService.selectByExample(accountRoleMapperExample);

        List<String> roleIds=accountRoleMapperList.stream().map(TSysAccountRoleMapper::getRoleId).collect(Collectors.toList());

        TSysRoleExample roleExample=new TSysRoleExample();
        roleExample.createCriteria().andRoleIdIn(roleIds);
        final List<TSysRole> roleList = roleService.selectByExample(roleExample);

        // 添加角色
        roleList.forEach(role->{
            authorizationInfo.addRole(role.getRoleSign());
        });

        final List<TSysAuthority> authorityList = roleAuthorityMapperService.selectAuthorityByRoleIds(roleIds);
        // 添加权限
        authorityList.forEach(authority->{
            authorizationInfo.addStringPermission(authority.getAuthSign());
        });
        return authorizationInfo;
    }


    /**
     * 登录验证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = String.valueOf(token.getPrincipal());
        String password = new String((char[]) token.getCredentials());
        // 通过数据库进行验证
        final TSysAccount account = accountService.authentication(username, PwdHashSaltUtils.againSha256Hex(username,password));
        if (account == null) {
            throw new AuthenticationException("当前输入的用户名或密码错误，请检查！");
        }else{
        	if(!account.getStatus().equals(1)){
                throw new LockedAccountException("当前账号已停用，请联系客服！");
        	}
            if (null!=account.getExpireTime()) {
                if (Instant.from(account.getExpireTime().atStartOfDay().atZone(ZoneId.systemDefault())).toEpochMilli() <= System.currentTimeMillis()) {
                    throw new LockedAccountException("当前账号已经过期，请联系客服！");
                }
            }

        }

        updateFinalLoginInfo(account);

        return new SimpleAuthenticationInfo(account, password, getName());

    }

    private void  updateFinalLoginInfo(TSysAccount account){
        //接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        //更改最后登陆信息
        String ip= IPUtils.getRealIP(request);
        account.setFinalLoginIp(ip);
        account.setFinalLoginTime(LocalDateTime.now());
        account.setFinalLoginLocation(Ip2RegionUtils.getCleanAddress(ip));
        accountService.updateByPrimaryKeySelective(account);
    }


    /**
     * 删除缓存
     *
     * @param principals
     */
    @Override
    protected void doClearCache(PrincipalCollection principals) {
        super.doClearCache(principals);
    }
}
